package com.sale.goods.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sale.common.core.constant.CacheNames;
import com.sale.common.core.exception.GlobalException;
import com.sale.common.core.utils.StringUtils;
import com.sale.common.mybatis.core.page.PageQuery;
import com.sale.common.mybatis.core.page.TableDataInfo;
import com.sale.common.redis.utils.CacheUtils;
import com.sale.common.satoken.utils.LoginHelper;
import com.sale.goods.domain.*;
import com.sale.goods.domain.dto.GoodsDisburseDto;
import com.sale.goods.domain.dto.GoodsPaymentDto;
import com.sale.goods.domain.dto.single.GoodsPaymentSingle;
import com.sale.goods.domain.vo.GoodsPaymentVo;
import com.sale.goods.mapper.GoodsCalculateMapper;
import com.sale.goods.mapper.GoodsDisburseMapper;
import com.sale.goods.mapper.GoodsPaymentMapper;
import com.sale.goods.mapper.GoodsSourceMapper;
import com.sale.goods.service.IGoodsPaymentService;
import com.sale.goods.service.IGoodsPaymentService;
import com.sale.order.api.RemoteSupplierService;
import com.sale.storage.api.RemotePurchaseReceiptService;
import com.sale.storage.api.vo.QuantityDataVo;
import com.sale.storage.api.vo.UpdateInvoicedQuantityVo;
import com.sale.system.api.RemoteAccountManagementService;
import com.sale.system.api.RemoteCodeService;
import com.sale.system.api.RemoteReviewService;
import com.sale.system.api.RemoteStaffManagementService;
import com.sale.system.api.domain.SysBalance;
import com.sale.system.api.domain.SysDictData;
import com.sale.system.api.domain.vo.SysAuditHistoryVo;
import com.sale.goods.api.dto.GoodsMessageBySupplierDto;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 付款单实现类
 * @Date 23-08-07
 * @Author hl
 **/
@RequiredArgsConstructor
@Service
public class GoodsPaymentServiceImpl implements IGoodsPaymentService {

    private final GoodsPaymentMapper goodsPaymentMapper;

    private final GoodsCalculateMapper goodsCalculateMapper;

    private final GoodsSourceMapper goodsSourceMapper;

    private final GoodsDisburseMapper goodsDisburseMapper;

    @DubboReference
    private final RemoteReviewService remoteReviewService;

    @DubboReference
    private final RemoteCodeService remoteCodeService;

    @DubboReference
    private final RemoteSupplierService remoteSupplierService;

    @DubboReference
    private final RemoteStaffManagementService remoteStaffManagementService;

    @DubboReference
    private final RemoteAccountManagementService remoteAccountManagementService;

    @DubboReference
    private final RemotePurchaseReceiptService remotePurchaseReceiptService;


    /**
     * 查询付款单
     *
     * @param goodSPaymentVo,pageQuery
     * @return 收款单集合
     */
    @Override
    public TableDataInfo<GoodsPaymentDto> selectPaymentList(GoodsPaymentVo goodSPaymentVo, PageQuery pageQuery) {
        Page<GoodsPaymentDto> page = goodsPaymentMapper.selectPaymentList(pageQuery.build(), this.buildQueryWrapper(goodSPaymentVo));
        List<SysDictData> netArray = CacheUtils.get(CacheNames.SYS_DICT, "bill_state");
        Map<String, String> netMap = netArray.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        List<SysDictData> netArray2 = CacheUtils.get(CacheNames.SYS_DICT, "goods_cancel_status");
        Map<String, String> netMap2 = netArray2.stream().collect(Collectors.toMap(SysDictData::getDictValue, SysDictData::getDictLabel));
        //供应商
        Map<String, String> supplierMap = remoteSupplierService.getOpenSupplierFinance();
        //职员
        Map<String, String> map = remoteStaffManagementService.selectAllStaffManagement();
        List<GoodsPaymentDto> list = page.getRecords();
        for (GoodsPaymentDto dto :
            list) {
            dto.setPaymentStatusDict(netMap.get(dto.getPaymentStatus()));
            dto.setCancelStatusDict(netMap2.get(dto.getCancelStatus()));
            dto.setSupplierName(supplierMap.get(dto.getSupplierCode()));
            dto.setBusinessName(map.get(dto.getBusinessName()));
        }
        return TableDataInfo.build(page);
    }

    private Wrapper<GoodsPaymentVo> buildQueryWrapper(GoodsPaymentVo goodsPaymentVo) {
        String name = goodsPaymentVo.getSupplierName();
        if (StringUtils.isNotBlank(name)) {
            String code = remoteSupplierService.getCodeBySupplierName(name);
            goodsPaymentVo.setSupplierName(code);
        }
        String name2 = goodsPaymentVo.getBusinessName();
        if (StringUtils.isNotBlank(name2)) {
            Long staffId = remoteStaffManagementService.selectStaffManagementName(name2);
            goodsPaymentVo.setBusinessName(String.valueOf(staffId));
        }
        QueryWrapper<GoodsPaymentVo> wrapper = Wrappers.query();
        wrapper
            .like(ObjectUtil.isNotNull(goodsPaymentVo.getPaymentCode()), "payment_code", goodsPaymentVo.getPaymentCode())
            .like(StringUtils.isNotBlank(goodsPaymentVo.getBusinessName()), "business_name", goodsPaymentVo.getBusinessName())
            .like(StringUtils.isNotBlank(goodsPaymentVo.getPaymentStatus()), "payment_status", goodsPaymentVo.getPaymentStatus())
            .eq(StringUtils.isNotBlank(goodsPaymentVo.getSupplierName()), "supplier_code", goodsPaymentVo.getSupplierCode())
            .eq(StringUtils.isNotBlank(goodsPaymentVo.getCancelStatus()), "cancel_status", goodsPaymentVo.getCancelStatus()).between(goodsPaymentVo.getBeginTime() != null && goodsPaymentVo.getEndTime() != null,
                "create_time", goodsPaymentVo.getBeginTime(), goodsPaymentVo.getEndTime());
        return wrapper;
    }

    /**
     * 新增收款单
     *
     * @param goodsPaymentVo
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertPayment(GoodsPaymentVo goodsPaymentVo) throws Exception {
        GoodsPayment coll = new GoodsPayment();
        BeanUtils.copyProperties(goodsPaymentVo, coll);
        Long id = IdWorker.getId();
        coll.setPaymentId(id);
        coll.setPaymentStatus(1);
        //新增明细(账户)
        List<GoodsCalculate> list = goodsPaymentVo.getCalculateList();
        //付款金额
        BigDecimal b1 = new BigDecimal(0);
        for (GoodsCalculate calculate :
            list) {
            b1 = b1.add(calculate.getAmountReceived());
            calculate.setRelevanceId(id);
        }
        coll.setPaymentAmount(b1);
        //新增账号明细
        goodsCalculateMapper.insertBatch(list);
        //源单据集合
        List<GoodsSource> list1 = goodsPaymentVo.getSourceList();
        //本次核销金额
        BigDecimal b2 = new BigDecimal(0);
        //单据金额
        if (list1 != null) {
            //新增源单据信息
            for (GoodsSource goodsSource :
                list1) {
                goodsSource.setRelevanceId(id);
                b2 = b2.add(goodsSource.getThisAmount());
            }
            goodsSourceMapper.insertBatch(list1);
        }
        coll.setPaymentCancelAmount(b2);
        coll.setPaymentShouldAmount(b1);
        coll.setPaymentHasAmount(b2);
        BigDecimal b3 = b1.subtract(b2);
        coll.setPaymentNotAmount(b3);
        if (b2.signum() > 0) {
            if (b3.signum() > 0) {
                //部分核销
                coll.setCancelStatus(1);
            } else {
                //全部核销
                coll.setCancelStatus(3);
            }
        } else {
            //未核销
            coll.setCancelStatus(2);
        }
        String authorityCoding = remoteCodeService.authorityCoding("finance:payment:index");
        if (authorityCoding == null) {
            throw new GlobalException("未进行单据配置,单据编码生成失败");
        }
        coll.setPaymentCode(authorityCoding);
        int os = goodsPaymentMapper.insert(coll);
        return os;
    }

    /**
     * 查询单个收款单
     *
     * @param paymentId
     * @return int
     */
    @Override
    public GoodsPaymentSingle selectPaymentById(long paymentId) {
        GoodsPayment Payment = goodsPaymentMapper.selectById(paymentId);
        GoodsPaymentSingle single = new GoodsPaymentSingle();
        BeanUtils.copyProperties(Payment, single);
        Map<String, Object> map = new HashMap<>();
        map.put("relevance_id", paymentId);
        List<GoodsCalculate> calculateList = goodsCalculateMapper.selectByMap(map);
        single.setCalculateList(calculateList);
        List<GoodsSource> sourceList = goodsSourceMapper.selectByMap(map);
        single.setSourceList(sourceList);
        return single;
    }

    /**
     * 删除单个收款单
     *
     * @param PaymentId
     * @return int
     */
    @Override
    public int deletePaymentById(Long PaymentId) {
        int os = goodsPaymentMapper.deleteById(PaymentId);
        //删除明细数据
        Map<String, Object> map = new HashMap<>();
        map.put("relevance_id", PaymentId);
        goodsCalculateMapper.deleteByMap(map);
        //删除源单据信息
        goodsSourceMapper.deleteByMap(map);
        return os;
    }

    /**
     * 修改收款单
     *
     * @param goodsPaymentVo
     * @return int
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updatePaymentEdit(GoodsPaymentVo goodsPaymentVo) {
        if (goodsPaymentVo.getPaymentStatus().equals("4")) {
            SysAuditHistoryVo vo = new SysAuditHistoryVo();
            vo.setPerms("finance:payment:iexamine");
            vo.setAuditDoc(goodsPaymentVo.getPaymentCode());
            int is = remoteReviewService.editHistory(vo);
            if (is == 0) {
                throw new GlobalException("修改失败,未找到审核历史!");
            }
        }
        GoodsPayment coll = new GoodsPayment();
        BeanUtils.copyProperties(goodsPaymentVo, coll);
        Long id = coll.getPaymentId();
        //删除明细数据 并新增
        Map<String, Object> map = new HashMap<>();
        map.put("relevance_id", id);
        goodsCalculateMapper.deleteByMap(map);
        //删除源单据信息
        goodsSourceMapper.deleteByMap(map);
        //新增明细(账户)
        List<GoodsCalculate> list = goodsPaymentVo.getCalculateList();
        //收款金额
        BigDecimal b1 = new BigDecimal(0);
        for (GoodsCalculate calculate :
            list) {
            b1 = b1.add(calculate.getAmountReceived());
            calculate.setRelevanceId(id);
        }
        coll.setPaymentAmount(b1);
        //新增账号明细
        goodsCalculateMapper.insertBatch(list);
        //源单据集合
        List<GoodsSource> list1 = goodsPaymentVo.getSourceList();
        //本次核销金额
        BigDecimal b2 = new BigDecimal(0);
        //单据金额
        if (list1 != null) {
            //新增源单据信息
            for (GoodsSource goodsSource :
                list1) {
                goodsSource.setRelevanceId(id);
                b2 = b2.add(goodsSource.getThisAmount());
            }
            goodsSourceMapper.insertBatch(list1);
        }
        coll.setPaymentCancelAmount(b2);
        coll.setPaymentShouldAmount(b1);
        coll.setPaymentHasAmount(b2);
        BigDecimal b3 = b1.subtract(b2);
        coll.setPaymentNotAmount(b3);
        if (b2.signum() > 0) {
            if (b3.signum() > 0) {
                //部分核销
                coll.setCancelStatus(1);
            } else {
                //全部核销
                coll.setCancelStatus(3);
            }
        } else {
            //未核销
            coll.setCancelStatus(2);
        }
        //新增主列表
        // coll.setPaymentStatus(1);

        int os = goodsPaymentMapper.updateById(coll);
        return os;
    }


    /**
     * 提交审核
     *
     * @param paymentId
     * @return int
     */
    @Override
    public int submitReview(Long paymentId) {
        GoodsPayment coll = goodsPaymentMapper.selectById(paymentId);
        int status = coll.getPaymentStatus();
        if (status != 1) {
            throw new GlobalException("只有待提交状态才能进行提交审核");
        }
        GoodsPayment coll2 = new GoodsPayment();
        coll2.setPaymentId(paymentId);
        coll2.setPaymentStatus(2);
        return goodsPaymentMapper.updateById(coll2);
    }

    /**
     * 撤销审核
     *
     * @param paymentId
     * @return int
     */
    @Override
    public int deleteReview(Long paymentId) {
        GoodsPayment coll = goodsPaymentMapper.selectById(paymentId);
        int status = coll.getPaymentStatus();
        if (status != 2) {
            throw new GlobalException("只有待审核状态才能进行撤销审核");
        }
        GoodsPayment coll2 = new GoodsPayment();
        coll2.setPaymentId(paymentId);
        coll2.setPaymentStatus(1);
        return goodsPaymentMapper.updateById(coll2);
    }

    /**
     * 审核单据
     *
     * @param goodsPaymentVo
     * @return int
     */
    @Override
    public int goodSExamineReview(GoodsPaymentVo goodsPaymentVo) throws Exception {
        SysAuditHistoryVo sysAuditHistoryVo = new SysAuditHistoryVo();
        Long id = goodsPaymentVo.getPaymentId();
        GoodsPayment coll = goodsPaymentMapper.selectById(id);
        String perms = "finance:payment:iexamine";
        sysAuditHistoryVo.setPerms(perms);
        sysAuditHistoryVo.setModuleType(3);
        sysAuditHistoryVo.setAuditState(goodsPaymentVo.getAuditState());
        sysAuditHistoryVo.setAuditRemarks(goodsPaymentVo.getAuditOpinion());
        sysAuditHistoryVo.setAuditDoc(coll.getPaymentCode());
        sysAuditHistoryVo.setUserId(LoginHelper.getUserId());
        int data = remoteReviewService.getSequence(sysAuditHistoryVo);
        if (data == 0) {
            throw new GlobalException("未对该审核进行配置");
        }
        //1:通过，2：审核中，3：没权限 4:该人已经审核过
        GoodsPayment goods = new GoodsPayment();
        goods.setPaymentId(id);
        switch (data) {
            case 1:
                if (goodsPaymentVo.getAuditState() == 2) {
                    goods.setPaymentStatus(4);
                } else {
                    goods.setPaymentStatus(5);
                    List<SysBalance> list1 = new ArrayList<>();
                    Map<String, Object> map2 = new HashMap<>();
                    map2.put("relevance_id", id);
                    List<GoodsCalculate> calculateList = goodsCalculateMapper.selectByMap(map2);
                    if (calculateList != null) {
                        for (GoodsCalculate calculate :
                            calculateList) {
                            SysBalance sys = new SysBalance();
                            sys.setAccountsId(Long.parseLong(calculate.getCalculateAccount()));
                            sys.setBalance(calculate.getAmountReceived());
                            list1.add(sys);
                        }
                        int j = remoteAccountManagementService.editListBalance2(list1);
                        if (j == 0) {
                            throw new GlobalException("未回传余额,请重试");
                        }
                        List<GoodsSource> list2 = goodsSourceMapper.selectByMap(map2);
                        List<GoodsCancel> cancelList = new ArrayList<>();
                        if (list2.size() > 0) {
                            List<QuantityDataVo> dataList = new ArrayList<>();
                            for (GoodsSource source :
                                list2) {
                                if (source.getSourceType().equals("其他支出")) {
                                    GoodsCancel cancel = new GoodsCancel();
                                    cancel.setApprovedAmount(source.getThisAmount());
                                    cancel.setReceiptNumber(source.getSourceCode());
                                    if (source.getUnwrittenAmount().subtract(source.getThisAmount()).compareTo(new BigDecimal(0)) > 0) {
                                        cancel.setStatus(1);
                                    } else {
                                        cancel.setStatus(3);
                                    }
                                    cancelList.add(cancel);
                                } else {
                                    QuantityDataVo vo = new QuantityDataVo();
                                    vo.setReceiptNumber(source.getSourceCode());
                                    vo.setQuantity("1");
                                    vo.setApprovedAmount(source.getThisAmount());
                                    vo.setDocumentType(source.getSourceType());
                                    dataList.add(vo);
                                }
                            }
                            UpdateInvoicedQuantityVo quantityVo = new UpdateInvoicedQuantityVo();
                            quantityVo.setList(dataList);
                            //客户的欠款更
                            boolean flag = remotePurchaseReceiptService.updateInvoicedQuantity(quantityVo);
                            if (!flag) {
                                throw new GlobalException("客户的欠款未更新,请重试");
                            }
                            if (!cancelList.isEmpty()) {
                                for (GoodsCancel ca :
                                    cancelList) {
                                    goodsDisburseMapper.updateDisburseCancel(ca);
                                }
                            }
                        }
                    }
                }
                break;
            case 2:
                goods.setPaymentStatus(3);
                break;
            case 3:
                if (data == 0) {
                    throw new GlobalException("不具备审核权限");
                }
                break;
            case 4:
                if (data == 0) {
                    throw new GlobalException("请勿重复审核");
                }
                break;
        }
        //审核人
        goods.setExamineBy(LoginHelper.getUsername());
        //审核日期
        goods.setExamineTime(new Date());
        return goodsPaymentMapper.updateById(goods);

    }

    /**
     * 工作台接口(销售已收款金额)
     */
    @Override
    public String goodsReceived() {
        return goodsPaymentMapper.goodsReceived();
    }

    /**
     * 工作台接口(采购未付款金额)
     */
    @Override
    public String goodsArrears() {
        return goodsPaymentMapper.goodsArrears();
    }

    /**
     * 根据供应商分组获取已核销金额、整单折扣
     */
    @Override
    public Map<String, GoodsMessageBySupplierDto> getGoodsMessageBySupplier() {
        List<GoodsMessageBySupplierDto> goodsMessageBySupplier = goodsPaymentMapper.getGoodsMessageBySupplier();
        Map<String, GoodsMessageBySupplierDto> map = new HashMap<>();
        for (GoodsMessageBySupplierDto entity : goodsMessageBySupplier) {
            map.put(entity.getDocumentNumber(), entity);
        }
        return map;
    }

}
